/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    device_i2c.c
 *  @brief   Designware i2c device adapter layer
 *  @version v1.0
 *  @date    03. Apr. 2023
 *  @author  liuchao
 ****************************************************************/

#include "mem_map_table.h"
#include "irq.h"
#include "crg.h"
#include "dw_i2c.h"
#include "device_i2c.h"

/**
 * @name	DesignWare I2C 0 Object Instantiation
 * @{
 */
#if (USE_DW_I2C_0)
static void dw_i2c_0_isr(void *ptr);
#define DW_I2C_0_REGBASE        (MEM_MAP_I2C0_BASE_ADDR)     /*!< designware i2c 0 relative baseaddr */
#define DW_I2C_0_INTNO          (I2C0_IRQn)         /*!< designware i2c 0 interrupt number  */
#define DW_I2C_0_SLVADDR        (0x57)                  /*!< i2c 0 slave address working in slave mode */
#define DW_I2C_0_TX_FIFO_LEN    (32)
#define DW_I2C_0_RX_FIFO_LEN    (32)
#define DW_I2C_0_MASTER_CODE    (0)
#define DW_I2C_0_TARADDR        (0x57)
#define DW_I2C_0_IC_CAPLOADING  (DW_I2C_CAP_LOADING_100PF)

DEV_I2C dw_i2c_0;                                       /*!< designware i2c object */
DW_I2C_CTRL dw_i2c_0_ctrl;                              /*!< designware i2c 0 ctrl */

/** designware i2c 0 open */
static int32_t dw_i2c_0_open(uint32_t mode, uint32_t param)
{
	return dw_i2c_open(&dw_i2c_0, mode, param);
}

/** designware i2c 0 close */
static int32_t dw_i2c_0_close(void)
{
	return dw_i2c_close(&dw_i2c_0);
}

/** designware i2c 0 control */
static int32_t dw_i2c_0_control(uint32_t ctrl_cmd, void *param)
{
	return dw_i2c_control(&dw_i2c_0, ctrl_cmd, param);
}

/** designware i2c 0 write */
static int32_t dw_i2c_0_write(const void *data, uint32_t len)
{
	return dw_i2c_write(&dw_i2c_0, data, len);
}

/** designware i2c 0 close */
static int32_t dw_i2c_0_read(void *data, uint32_t len)
{
	return dw_i2c_read(&dw_i2c_0, data, len);
}

/** designware i2c 0 interrupt routine */
static void dw_i2c_0_isr(void *ptr)
{
	dw_i2c_isr(&dw_i2c_0, ptr);
}

/** install designware i2c 0 to system */
static void dw_i2c_0_install(void)
{
	uint32_t i2c_abs_base = 0;
	DEV_I2C_PTR dw_i2c_ptr = &dw_i2c_0;
	DEV_I2C_INFO_PTR dw_i2c_info_ptr = &(dw_i2c_0.i2c_info);
	DW_I2C_CTRL_PTR dw_i2c_ctrl_ptr = &dw_i2c_0_ctrl;
	DW_I2C_REG_PTR dw_i2c_reg_ptr;

	/* Info init */
	dw_i2c_info_ptr->i2c_ctrl = (void *)dw_i2c_ctrl_ptr;
	dw_i2c_info_ptr->opn_cnt = 0;
	dw_i2c_info_ptr->addr_mode = I2C_7BIT_ADDRESS;
	dw_i2c_info_ptr->tar_addr = DW_I2C_0_TARADDR;
	/*
	 * get absolute designware base address
	 */
	i2c_abs_base = (uint32_t)DW_I2C_0_REGBASE;
	dw_i2c_reg_ptr = (DW_I2C_REG_PTR)(long)i2c_abs_base;

	/* i2c ctrl init */
	dw_i2c_ctrl_ptr->i2c_id = DW_I2C_0_ID;
	dw_i2c_ctrl_ptr->dw_i2c_regs = dw_i2c_reg_ptr;
	/* Variables which should be set during object implementation */
	dw_i2c_ctrl_ptr->ic_clkhz = get_mod_clk_rate(CRG_MOD_I2C0);
	dw_i2c_ctrl_ptr->ic_caploading = DW_I2C_0_IC_CAPLOADING;
	dw_i2c_ctrl_ptr->support_modes = DW_I2C_BOTH_SUPPORTED;
	dw_i2c_ctrl_ptr->tx_fifo_len = DW_I2C_0_TX_FIFO_LEN;
	dw_i2c_ctrl_ptr->rx_fifo_len = DW_I2C_0_RX_FIFO_LEN;
	dw_i2c_ctrl_ptr->i2c_master_code = DW_I2C_0_MASTER_CODE;
	dw_i2c_ctrl_ptr->retry_cnt = DW_I2C_MAX_RETRY_COUNT;
	dw_i2c_ctrl_ptr->intno = DW_I2C_0_INTNO;
	dw_i2c_ctrl_ptr->dw_i2c_int_handler = dw_i2c_0_isr;
	/* Variables which always change during i2c operation */
	dw_i2c_ctrl_ptr->int_status = 0;
	dw_i2c_ctrl_ptr->i2c_tx_over = 0;
	dw_i2c_ctrl_ptr->i2c_rx_over = 0;

	/** i2c dev init */
	dw_i2c_ptr->i2c_open = dw_i2c_0_open;
	dw_i2c_ptr->i2c_close = dw_i2c_0_close;
	dw_i2c_ptr->i2c_control = dw_i2c_0_control;
	dw_i2c_ptr->i2c_write = dw_i2c_0_write;
	dw_i2c_ptr->i2c_read = dw_i2c_0_read;
}
#endif /* USE_DW_I2C_0 */
/** @} end of name */

/**
 * @name	 DesignWare I2C 1 Object Instantiation
 * @{
 */
#if (USE_DW_I2C_1)
static void dw_i2c_1_isr(void *ptr);
#define DW_I2C_1_REGBASE        (MEM_MAP_I2C1_BASE_ADDR)     /*!< designware i2c 1 relative baseaddr */
#define DW_I2C_1_INTNO          (I2C1_IRQn)         /*!< designware i2c 1 interrupt number  */
#define DW_I2C_1_SLVADDR        (0x56)                  /*!< i2c 1 slave address working in slave mode */
#define DW_I2C_1_TX_FIFO_LEN    (32)
#define DW_I2C_1_RX_FIFO_LEN    (32)
#define DW_I2C_1_MASTER_CODE    (1)
#define DW_I2C_1_TARADDR        (0x56)
#define DW_I2C_1_IC_CAPLOADING  (DW_I2C_CAP_LOADING_100PF)

DEV_I2C dw_i2c_1;                                       /*!< designware i2c 1 object */
DW_I2C_CTRL dw_i2c_1_ctrl;                              /*!< designware i2c 1 ctrl */

/** designware i2c 1 open */
static int32_t dw_i2c_1_open(uint32_t mode, uint32_t param)
{
	return dw_i2c_open(&dw_i2c_1, mode, param);
}

/** designware i2c 1 close */
static int32_t dw_i2c_1_close(void)
{
	return dw_i2c_close(&dw_i2c_1);
}

/** designware i2c 1 control */
static int32_t dw_i2c_1_control(uint32_t ctrl_cmd, void *param)
{
	return dw_i2c_control(&dw_i2c_1, ctrl_cmd, param);
}

/** designware i2c 1 write */
static int32_t dw_i2c_1_write(const void *data, uint32_t len)
{
	return dw_i2c_write(&dw_i2c_1, data, len);
}

/** designware i2c 1 close */
static int32_t dw_i2c_1_read(void *data, uint32_t len)
{
	return dw_i2c_read(&dw_i2c_1, data, len);
}

/** designware i2c 1 interrupt routine */
static void dw_i2c_1_isr(void *ptr)
{
	dw_i2c_isr(&dw_i2c_1, ptr);
}

/** install designware i2c 1 to system */
static void dw_i2c_1_install(void)
{
	uint32_t i2c_abs_base = 0;
	DEV_I2C_PTR dw_i2c_ptr = &dw_i2c_1;
	DEV_I2C_INFO_PTR dw_i2c_info_ptr = &(dw_i2c_1.i2c_info);
	DW_I2C_CTRL_PTR dw_i2c_ctrl_ptr = &dw_i2c_1_ctrl;
	DW_I2C_REG_PTR dw_i2c_reg_ptr;

	/* Info init */
	dw_i2c_info_ptr->i2c_ctrl = (void *)dw_i2c_ctrl_ptr;
	dw_i2c_info_ptr->opn_cnt = 0;
	dw_i2c_info_ptr->addr_mode = I2C_7BIT_ADDRESS;
	dw_i2c_info_ptr->tar_addr = DW_I2C_1_TARADDR;
	/*
	 * get absolute designware base address
	 */
	i2c_abs_base = (uint32_t)DW_I2C_1_REGBASE;
	dw_i2c_reg_ptr = (DW_I2C_REG_PTR)(long)i2c_abs_base;

	/* i2c ctrl init */
	dw_i2c_ctrl_ptr->i2c_id = DW_I2C_1_ID;
	dw_i2c_ctrl_ptr->dw_i2c_regs = dw_i2c_reg_ptr;
	/* Variables which should be set during object implementation */
	dw_i2c_ctrl_ptr->ic_clkhz = get_mod_clk_rate(CRG_MOD_I2C1);
	dw_i2c_ctrl_ptr->ic_caploading = DW_I2C_1_IC_CAPLOADING;
	dw_i2c_ctrl_ptr->support_modes = DW_I2C_BOTH_SUPPORTED;
	dw_i2c_ctrl_ptr->tx_fifo_len = DW_I2C_1_TX_FIFO_LEN;
	dw_i2c_ctrl_ptr->rx_fifo_len = DW_I2C_1_RX_FIFO_LEN;
	dw_i2c_ctrl_ptr->i2c_master_code = DW_I2C_1_MASTER_CODE;
	dw_i2c_ctrl_ptr->retry_cnt = DW_I2C_MAX_RETRY_COUNT;
	dw_i2c_ctrl_ptr->intno = DW_I2C_1_INTNO;
	dw_i2c_ctrl_ptr->dw_i2c_int_handler = dw_i2c_1_isr;
	/* Variables which always change during i2c operation */
	dw_i2c_ctrl_ptr->int_status = 0;
	dw_i2c_ctrl_ptr->i2c_tx_over = 0;
	dw_i2c_ctrl_ptr->i2c_rx_over = 0;

	/** i2c dev init */
	dw_i2c_ptr->i2c_open = dw_i2c_1_open;
	dw_i2c_ptr->i2c_close = dw_i2c_1_close;
	dw_i2c_ptr->i2c_control = dw_i2c_1_control;
	dw_i2c_ptr->i2c_write = dw_i2c_1_write;
	dw_i2c_ptr->i2c_read = dw_i2c_1_read;
}
#endif /* USE_DW_I2C_1 */
/** @} end of name */

/**
 * @brief	install all i2c objects
 * @note	@b MUST be called during system init
 */
static void dw_i2c_all_install(void)
{
#if (USE_DW_I2C_0)
	dw_i2c_0_install();
#endif
#if (USE_DW_I2C_1)
	dw_i2c_1_install();
#endif
}

/** get one designware device structure */
DEV_I2C_PTR i2c_get_dev(int32_t i2c_id)
{
	static uint32_t install_flag = 0;

	/* intall device objects */
	if (install_flag == 0) {
		install_flag = 1;
		dw_i2c_all_install();
	}

	switch (i2c_id) {
#if (USE_DW_I2C_0)
		case DW_I2C_0_ID:
			return &dw_i2c_0;
#endif

#if (USE_DW_I2C_1)
		case DW_I2C_1_ID:
			return &dw_i2c_1;
#endif

		default:
			break;
	}

	return NULL;
}
